package com.sndscl.rpc.spring;

import com.sndscl.rpc.common.annotation.SndsclRpcInterface;
import com.sndscl.rpc.common.constant.SndSclConstant;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

/**
 * @Description 接口实例注入到Spring容器
 * @Author lsh
 * @Date 2020/10/16 14:49
 **/
@Component
public class SndsclRpcBeanDefinitionRegister implements BeanDefinitionRegistryPostProcessor, ResourceLoaderAware, ApplicationContextAware {

    private static String DEFAULT_RESOURCE_PATTERN = "**/*.class";
    private ApplicationContext applicationContext;
    private ResourcePatternResolver resourcePatternResolver;
    private MetadataReaderFactory metadataReaderFactory;

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        Set<Class<?>> beanClazzs = scanRpcCallPackage();
        for(Class<?> beanclazz : beanClazzs){
            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(beanclazz);
            GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanDefinitionBuilder.getRawBeanDefinition();
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanclazz);
            //设置beanFactory，通过BenFactory获得对象实例
            beanDefinition.setBeanClass(SndsclRpcBenFactory.class);
            //设置注入方式，使用byType注入
            beanDefinition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
            beanDefinitionRegistry.registerBeanDefinition(beanclazz.getSimpleName(),beanDefinition);
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
        this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
    }

    private Set<Class<?>>  scanRpcCallPackage(){
        Set<Class<?>> clazzSet = new HashSet<>();
        String basePackage = this.getEnvironment().getProperty(SndSclConstant.SPRING_PRO_SNDSCL_SCANNER_PACKAGE);
        if(basePackage == null){
            System.err.println("SNDSCL RPC INIT ERROR,"+SndSclConstant.SPRING_PRO_SNDSCL_SCANNER_PACKAGE+" NOT CONFIG!");
            return null;
        }
        String packageScanPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                ClassUtils.convertClassNameToResourcePath(this.getEnvironment().resolveRequiredPlaceholders(basePackage))
                + "/"+DEFAULT_RESOURCE_PATTERN;
        try {
            Resource[] resources = resourcePatternResolver.getResources(packageScanPath);
            for(Resource resource : resources){
                if(resource.isReadable()){
                    MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
                    String className = metadataReader.getClassMetadata().getClassName();
                    System.out.println(className);
                    try {
                        Class<?> clazz = Class.forName(className);
                        SndsclRpcInterface sndsclRpcInterface = clazz.getAnnotation(SndsclRpcInterface.class);
                        if(sndsclRpcInterface != null){
                            clazzSet.add(clazz);
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return clazzSet;
    }

    private Environment getEnvironment(){
        return applicationContext.getEnvironment();
    }

}
